package com.knife.common.tree.builder.impl;


import com.knife.common.tree.annotations.KnifeTreeId;
import com.knife.common.tree.annotations.KnifeTreeParentId;
import com.knife.common.tree.builder.KnifeTreeBuilder;
import com.knife.common.tree.dto.ElementUiTree;
import com.knife.common.tree.utils.KnifeTreeUtil;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;

/**
 * 饿了么ui前端树构造
 *
 * @author： 76875
 * @date： 2022/6/6 星期一 18:16
 * @description：
 * @modifiedBy：
 * @version: 1.0
 */
@SuppressWarnings("ALL")
public class ElementUiKnifeTreeBuilder<E, T extends ElementUiTree> implements KnifeTreeBuilder<E, T> {

    private Function<E, T> covertFunction;

    public ElementUiKnifeTreeBuilder(Function<E, T> covertFunction) {
        this.covertFunction = covertFunction;
    }

    @Override
    public List<T> buildMultiRootTree(List<E> dataList) throws IllegalAccessException {
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        // 1. 找到本类的唯一键和父键
        Field treeIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeId.class);
        Field treeParentIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeParentId.class);
        // 2. 根据父键的类型，找到符合条件的根节点
        List<E> rootList = KnifeTreeUtil.getRootList(treeIdField, treeParentIdField, dataList);
        // 使用 linkedList
        LinkedList<E> dataLinkedList = new LinkedList<>(dataList);
        List<T> elementUiTreeRootList = new ArrayList<>();
        rootList.forEach(item -> elementUiTreeRootList.add(covertFunction.apply(item)));
        // 移除根节点
        dataLinkedList.removeAll(rootList);
        // 3. 遍历每一个根节点，找其他记录的父键为本记录唯一键的所有记录，递归遍历
        for (ElementUiTree elementUiTree : elementUiTreeRootList) {
            Set<E> usedSet = new HashSet<>();
            create(elementUiTree, usedSet, dataLinkedList, treeParentIdField);
            dataLinkedList.removeAll(usedSet);
        }
        return elementUiTreeRootList;
    }

    @Override
    public <V> List<T> buildMultiRootTree(List<E> dataList, V rootValue) throws IllegalAccessException {
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        // 1. 找到本类的唯一键和父键
        Field treeIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeId.class);
        Field treeParentIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeParentId.class);
        // 2. 根据父键的类型，找到符合条件的根节点
        List<E> rootList = KnifeTreeUtil.getRootList(treeIdField, dataList, rootValue);
        // 使用 linkedList
        LinkedList<E> dataLinkedList = new LinkedList<>(dataList);
        List<T> elementUiTreeRootList = new ArrayList<>();
        rootList.forEach(item -> elementUiTreeRootList.add(covertFunction.apply(item)));
        // 移除根节点
        dataLinkedList.removeAll(rootList);
        // 3. 遍历每一个根节点，找其他记录的父键为本记录唯一键的所有记录，递归遍历
        for (ElementUiTree elementUiTree : elementUiTreeRootList) {
            Set<E> usedSet = new HashSet<>();
            create(elementUiTree, usedSet, dataLinkedList, treeParentIdField);
            dataLinkedList.removeAll(usedSet);
        }
        return elementUiTreeRootList;
    }

    private void create(ElementUiTree elementUiTree, Set<E> usedSet, List<E> dataList, Field treeParentIdField) throws IllegalAccessException {
        List<ElementUiTree> elementUiTrees = new ArrayList<>();
        for (E e : dataList) {
            Object o = FieldUtils.readField(treeParentIdField, e, true);
            Integer id = elementUiTree.getId();
            if (Objects.equals(id, o) && !usedSet.contains(e)) {
                ElementUiTree newTreeNode = covertFunction.apply(e);
                elementUiTrees.add(newTreeNode);
                usedSet.add(e);
                create(newTreeNode, usedSet, dataList, treeParentIdField);
            }
        }
        elementUiTree.setChildren(elementUiTrees);
    }

    @Override
    public <RootValue> T buildSingleRootTree(List<E> dataList, RootValue rootValue) throws IllegalAccessException {
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        // 1. 找到本类的唯一键和父键
        Field treeIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeId.class);
        Field treeParentIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeParentId.class);
        E root = KnifeTreeUtil.getRoot(treeIdField, dataList, rootValue);
        LinkedList<E> dataLinkedList = new LinkedList<>(dataList);
        dataLinkedList.remove(root);
        T elementUiTree = covertFunction.apply(root);
        Set<E> usedSet = new HashSet<>();
        create(elementUiTree, usedSet, dataLinkedList, treeParentIdField);
        return elementUiTree;
    }

    @Override
    public T buildSingleRootTree(List<E> dataList) throws IllegalAccessException {
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        // 1. 找到本类的唯一键和父键
        Field treeIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeId.class);
        Field treeParentIdField = KnifeTreeUtil.getAnnotationField(dataList.get(0).getClass(), KnifeTreeParentId.class);
        E root = KnifeTreeUtil.getRoot(treeIdField,treeParentIdField ,dataList);
        LinkedList<E> dataLinkedList = new LinkedList<>(dataList);
        dataLinkedList.remove(root);
        T elementUiTree = covertFunction.apply(root);
        Set<E> usedSet = new HashSet<>();
        create(elementUiTree, usedSet, dataLinkedList, treeParentIdField);
        return elementUiTree;
    }
}
